package com.qd.hik.service;

import com.cdqidi.exception.ApiException;
import com.cdqidi.httpclientbootstart.util.HttpUtil;
import com.cdqidi.util.JacksonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.qd.hik.base.HkBaseTokenDTO;
import com.qd.hik.dto.HkBaseHttpResp;
import com.qd.hik.dto.charge.*;
import com.qd.hik.token.HkAccessToken;
import com.qd.hik.token.HkAccessTokenManager;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * 临停
 *
 * @author sjk
 * @create 2024-05-30 11:40
 * @since 1.0.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
@HkAccessToken
public class HkChargeService {
    /**
     * 2.7.1 临停缴费下单
     */
    private static final String CHARGE_PAYMENT_URL = "/artemis/api/v1/charge/payment";
    /**
     * 2.7.2 停车订单列表
     */
    private static final String CHARGE_PARK_ORDERS_URL = "/artemis/api/v1/charge/parkOrders";
    /**
     * 2.7.3 停车订单详情
     */
    private static final String CHARGE_PARK_ORDERS_DETAIL_URL = "/artemis/api/v1/charge/parkOrders/detail";
    /**
     * 2.7.4 可使用的优惠券列表
     */
    private static final String CHARGE_PARK_ORDERS_USABLE_COUPONS_URL = "/artemis/api/v1/charge/parkOrders/usableCoupons";
    /**
     * 2.7.5 在停订单查询
     */
    private static final String CHARGE_PARK_ORDERS_PARKING_URL = "/artemis/api/v1/charge/order/parking";
    /**
     * 2.7.6 批量补缴下单
     */
    private static final String CHARGE_PAYMENT_BATCH_URL = "/artemis/api/v1/charge/payment/batch";
    /**
     * 2.7.7 提交订单申诉
     */
    private static final String CHARGE_PARK_ORDERS_APPEAL_URL = "/artemis/api/v1/charge/parkOrders/appeal";
    /**
     * 2.7.8 支付状态查询
     */
    private static final String CHARGE_PAYMENT_RESULT_URL = "/artemis/api/v1/charge/payment/result";
    /**
     * 2.7.9 订单已支付记录
     */
    private static final String CHARGE_PAY_RECORDS_RESULT_URL = "/artemis/api/v1/charge/parkOrders/payRecords";
    /**
     * 2.7.10 订单申诉详情
     */
    private static final String CHARGE_APPEAL_DETAIL_URL = "/artemis/api/v1/charge/parkOrders/appeal/detail";
    /**
     * 2.4.3 获取车牌欠费记录
     */
    private static final String CHARGE_GET_ARREARS_RECORDS_URL = "/artemis/api/v1/charge/getArrearsRecords";
    /**
     * 2.4.2 停车账单支付通知
     */
    private static final String CHARGE_PAYMENT_NOTICE_URL = "/artemis/api/v1/charge/payment/notice";
    /**
     * 2.4.4 欠费补缴通知
     */
    private static final String CHARGE_PAY_ARREARS_FEE_URL = "/artemis/api/v1/charge/payArrearsFee";
    /**
     * 2.4.1 停车账单查询
     */
    private static final String CHARGE_PAYMENT_INFO_URL = "/artemis/api/v1/charge/getParkingPaymentInfo";

    private final HkBaseTokenDTO hkBaseTokenDTO;
    private final HttpUtil httpUtil;
    private final ObjectMapper objectMapper;

    /**
     * 2.7.1 临停缴费下单
     *
     * @param req 临停缴费
     */
    @SneakyThrows
    public HkBaseHttpResp<HkPaymentResp> payment(HkPaymentReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PAYMENT_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.2 停车订单列表
     *
     * @param req 停车订单
     */
    @SneakyThrows
    public HkBaseHttpResp<HkParkOrdersResp> parkOrders(HkParkOrdersReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PARK_ORDERS_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        log.info("2.7.2 停车订单列表,请求参数: {},返回值: {}", json, post);
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.3 停车订单详情
     *
     * @param req 停车订单
     */
    @SneakyThrows
    public HkBaseHttpResp<HkParkOrdersDetailResp> parkOrdersDetail(HkParkOrdersDetailReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PARK_ORDERS_DETAIL_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.4 可使用的优惠券列表
     *
     * @param req 可使用的优惠券
     */
    @SneakyThrows
    public HkBaseHttpResp<List<HkUsableCouponsResp>> parkOrdersUsableCoupons(HkUsableCouponsReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PARK_ORDERS_USABLE_COUPONS_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.5 在停订单查询
     *
     * @param req 在停订单
     */
    @SneakyThrows
    public HkBaseHttpResp<HkParkOrderParkingResp> parkOrdersParking(HkParkOrderParkingReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PARK_ORDERS_PARKING_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        log.info("在停订单查询,请求参数: {},返回值: {}", json, post);
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.6 批量补缴下单
     *
     * @param req 在停订单
     */
    @SneakyThrows
    public HkBaseHttpResp<HkPaymentBatchResp> paymentBatch(HkPaymentBatchReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PAYMENT_BATCH_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.7 提交订单申诉
     *
     * @param req 在停订单
     * @return 成功 or 失败
     */
    @SneakyThrows
    public HkBaseHttpResp<?> parkOrdersAppeal(HkParkOrdersAppealReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PARK_ORDERS_APPEAL_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, HkBaseHttpResp.class);
    }

    /**
     * 2.7.8 支付状态查询
     *
     * @param billNo 下单编号
     */
    @SneakyThrows
    public HkBaseHttpResp<HkPaymentResultResp> paymentResult(String billNo) {
        String json = objectMapper.createObjectNode().put("billNo", billNo).toString();
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PAYMENT_RESULT_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.9 订单已支付记录
     *
     * @param uniqueId 订单标识
     * @param parkCode 停车场编号
     */
    @SneakyThrows
    public HkBaseHttpResp<List<HkPayRecordsResp>> payRecords(String uniqueId, String parkCode) {
        String json = objectMapper.createObjectNode().put("uniqueId", uniqueId).put("parkCode", parkCode).toString();
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PAY_RECORDS_RESULT_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.7.10 订单申诉详情
     *
     * @param uniqueId 订单标识
     * @param parkCode 停车场编号
     */
    @SneakyThrows
    public HkBaseHttpResp<HkAppealDetailResp> appealDetail(String uniqueId, String parkCode) {
        String json = objectMapper.createObjectNode().put("uniqueId", uniqueId).put("parkCode", parkCode).toString();
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_APPEAL_DETAIL_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.4.3 获取车牌欠费记录
     *
     * @param plateNo    车牌号
     * @param plateColor 车牌颜色
     */
    @SneakyThrows
    public HkBaseHttpResp<List<HkArrearsRecordsResp>> getArrearsRecords(String plateNo, Integer plateColor) {
        ObjectNode objectNode = objectMapper.createObjectNode().put("plateNo", plateNo);
        if (null != plateColor) {
            objectNode.put("plateColor", plateColor);
        }
        String json = objectNode.toString();
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_GET_ARREARS_RECORDS_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        log.info("2.4.3 获取车牌欠费记录,请求参数: {},返回值: {}", json, post);
        return objectMapper.readValue(post, new TypeReference<>() {
        });
    }

    /**
     * 2.4.2 停车账单支付通知
     *
     * @param req 参数
     */
    @SneakyThrows
    public HkBaseHttpResp<?> paymentNotice(HkPaymentNoticeReq req) {
//        log.info("url: {}", hkBaseTokenDTO.getBaseUrl() + CHARGE_PAYMENT_NOTICE_URL);
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PAYMENT_NOTICE_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        log.info("2.4.2 停车账单支付通知,请求参数: {},返回值: {}", json, post);
        return objectMapper.readValue(post, HkBaseHttpResp.class).setReqJson(json);
    }

    /**
     * 2.4.4 欠费补缴通知
     *
     * @param req 参数
     */
    @SneakyThrows
    public HkBaseHttpResp<HkPayArrearsFeeResp> payArrearsFee(HkPayArrearsFeeReq req) {
        String json = JacksonUtil.getObjectMapper().writeValueAsString(req);
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PAY_ARREARS_FEE_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        log.info("2.4.4 欠费补缴通知,请求参数: {},返回值: {}", json, post);
        HkBaseHttpResp<HkPayArrearsFeeResp> resp = objectMapper.readValue(post, new TypeReference<>() {
        });
        resp.setReqJson(json);
        return resp;
    }

    /**
     * 2.4.1 停车账单查询
     *
     * @param plateNo 车牌号
     */
    @SneakyThrows
    public HkBaseHttpResp<HkPaymentInfoResp> paymentInfo(String plateNo) {
        if (!StringUtils.hasLength(plateNo)) {
            throw new ApiException("车牌号不能为空");
        }
        String json = objectMapper.createObjectNode().put("plateNo", plateNo).put("isQuery",0).toString();
        String post = httpUtil.sendHttpsPost(hkBaseTokenDTO.getBaseUrl() + CHARGE_PAYMENT_INFO_URL, json, Map.of("access_token", HkAccessTokenManager.getToken().getAccessToken()));
        log.info("2.4.1 停车账单查询,请求参数: {},返回值: {}", json, post);
        HkBaseHttpResp<HkPaymentInfoResp> resp = objectMapper.readValue(post, new TypeReference<>() {
        });
        if (resp.isSuccess()) {
            HkPaymentInfoResp data = resp.getData();
            if (null != data) {
                if (!Objects.equals(data.getTotalCost(), data.getPayMoney())) {
                    log.error("2.4.1 停车账单查询,海康查询订单总收费金额和待支付金额不匹配,json: {}", resp.getReqJson());
                }
            }
        }
        return resp;
    }


    public void parkOrders(Integer pageNo, Integer requestType, String mobile, Set<HkParkOrdersResp.Results> list) {
        HkParkOrdersReq req = new HkParkOrdersReq();
        req.setPageNo(pageNo);
        req.setPageSize(99);
        req.setPhone(mobile);
        if (null != requestType) {
            req.setRequestType(String.valueOf(requestType));
        }
        final HkBaseHttpResp<HkParkOrdersResp> resp = parkOrders(req);
        req.freeData();
        if (resp.isSuccess()) {
            if (null == resp.getData().getResults() || resp.getData().getResults().isEmpty()) {
                return;
            }
            list.addAll(resp.getData().getResults());
            parkOrders(pageNo + 1, requestType, mobile, list);
        } else {
            throw new ApiException(resp.getMsg());
        }
    }
}